<?php
/*
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

/*
ArraToTable Class
=================

Maybe a better name would be  "Array to something that looks like a table" 
but thats a pretty ugly name.

Basically you support some  array whith data and the class renders the 
full output of this data. It really doesn't matter if the array contains some 
scientific data or mabe the boxes displayed on you HTML page. As you can 
simply define an external template file  its pretty easy to adapt to 
anything you like.

Besides from a few helper functions i tried to write this class in a way you can simply 
read it from top down to understand whats going on. I really hate classes where you have 
to jump forth and back between tons of unsorted methods while trying to figure out whats 
actually going on.

Left most vars to public as i had no intention to flood the class whith tons of getters and setters.

Basic call to this class looks like:
	$oAtt=new ArrayToTable();
	$oAtt->aData =$aYourArrayWhithData;
	echo ($oAtt->Create());
And Whoops you got a table ready...
For more examples take a look into the example files.

*/

class ArrayToTable {

	/////////////////////////////////////////////////////////////////////
	// Variable declarations and defaults
	/////////////////////////////////////////////////////////////////////

	// Main data array and its properties
	public $aData = ""; //if its =="" its no array someone forgot to put data in it  ;-)
	private $iDataCols = 0; //set automatic , number of columns in Data Array
	private $iDataRows = 0; //set automatic , number of rows in Data Array
	
	public $sAdapt1D = ""; // "row", "col", "" convert 1D array to single row , column , or do nothing
	
	public $iTablify = 0; //default 0 ,  number of columns to convert to
	
	//Some Settings for the main wrapper/table construct
	public $sCaption = ""; // no content no Caption
	public $sCaptionClass = "hline"; // class for your caption (mostly needed whith DIV based templates)
	public $sWrapperClass = "att"; // classes for the wrapper div
	public $sWrapperExtra =''; // want to set an id or maybe some borders for debug , this is the place. Just use normal html atribut syntax.
	public $sTableClass = "dtable"; //classes for the actual table element
	public $sTableExtra = ''; // want to set an id or maybe some borders for debug , this is the place. Just use normal html atribut syntax.
 
	// default classes for TR, TH and TD elements 
	// Mainly used for some javascript addressing like sortable rows
	// classes are simple space separated list like "class1 class2 class3"
	public $sDefaultTrExtra='';           //default extra for all <tr> exept in thead and tfoot
	public $sDefaultTrClasses='row';      //default classes for all <tr> exept in thead and tfoot 
	public $sDefaultTdExtra='';           //default extra for all <td> exept in thead and tfoot
	public $sDefaultTdClasses='col';      //default classes for all <td> exept in thead and tfoot

	public $sDefaultThExtra='';           //default extra for all <th>  (in header) 
	public $sDefaultThClasses='hcol';     //default classes for all <th> (in header)
	public $sColHeadClass= "hcol-";       //number of column 1 2 3  4 5 6 7 8
	public $sRColHeadClass= "rhcol-";	 //reverted number of colums 8 7 6 5 4 3 2 1 
	public $sColTypeHeadClass= "hcoltype-"; //different colums whith different colors for example

	public $sDefaultTdFootExtra='';        //default extra for all <td> in footer
	public $sDefaultTdFootClasses='fcol';  //default classes for all <td> in footer
	public $sColFootClass= "fcol-";        //number of column 1 2 3  4 5 6 7 8
	public $sRColFootClass= "rfcol-";	  //reverted number of colums 8 7 6 5 4 3 2 1 
	public $sColTypeFootClass= "fcoltype-"; //different colums whith different colors for example
		
	public $sDefaultTrHeadExtra='';       //default extra for all <tr> in thead  
	public $sDefaultTrHeadClasses='hrow';//default classes for all <tr> in thead
	
	public $sDefaultTrFootExtra='';       //default extra for all <tr> in footer 
	public $sDefaultTrFootClasses='frow';//default classes for all <tr> in footer
	
	// you want different cycling colors/types for your rows ?
	public $iMaxRowTypes = 1; // Default 1 just one Rowtype (2 Typen : 1,2)
	
	//classnametemplates for rows
	public $sRowTypeClass= "rowtype-"; //different rows whith different colors for example
	public $sRowClass= "row-"; // row number  1 2 3  4 5 6 7 8
	public $sRRowClass= "rrow-"; // reverted row number 8 7 6 5 4 3 2 1 
	
	// you want different cycling colors/types for your cols ?
	public $iMaxColTypes = 1; // Default 1 (3 Typen: 1,2,3);
	
	//classnametemplates for colums
	public $sColTypeClass= "coltype-"; //different colums whith different colors for example
	public $sColClass= "col-"; //number of column 1 2 3  4 5 6 7 8
	public $sRColClass= "rcol-";	//reverted number of colums 8 7 6 5 4 3 2 1 
	public $sColRowClass= "colrow-";     //number of rows 1 2 3  4 5 6 7 8  (rownumber defined in column field)
	public $sRColRowClass= "rcolrow-";	//reverted number of rows 8 7 6 5 4 3 2 1 (rrownumber defined in column field)

	//Footer and header settings
	public $sHeadAutoFetch = ""; // ""=do nothing, "keys"=fetch the headline from keys, "first"= fetch from first row, "last"=fetch last row
	public $sFootAutoFetch = ""; // ""=do nothing, "keys"=fetch the footer from keys, "first"= fetch from first row, "last"=fetch last row
	public $aHeader= "";//if its =="" its no array someone forgot to put data in it  ;-) + needs the same amount of colums as the Data Array
	private $iHeaderCols= 0; //is set automatically by _Init 
	public $aFooter= "";//if its =="" its no array someone forgot to put data in it  ;-) + needs the same amount of colums as the Data Array
	private $iFooterCols= 0; //is set automatically by _Init 	
	
	//template settings
	public $sAlternativTemplate =""; //if empty , we use the default one
	public $bIsTableTemplate = true; // Is this a Table or maybe a Div Template, Tables can use Colspan and Rowspan

	// IMPORTANT !!!! WE CAN USE  \n \t INSIDE SINGLEQUOTES HERE !!!!
	private $aTpl=array  (  //actually the template default array
		"WrapStart"      => '<div class="%1$s" %2$s >\n', // %1 full class attrib, %2 extrastuff  ID, border, whatever
		"TabStart"       => '\t<table class="%1$s" %2$s >\n', // %1 liste der Klassen  %2 extrastuff ID, border, whatever
		"TabCaption"     => '\t\t<caption class="%1$s" >%2$s</caption>\n', // %1 classes for caption,  %2 The Headline (Caption)
		"TabColgroup"    => '\t\t\n', //if you really need this, this is a place to put the whole <colgroup> stuff
		
		"TabHeadStart"   => '\t\t<thead>\n',
		"TabHeadRowStart"=> '\t\t\t<tr class="%1$s" %2$s >\n', // %1 = classes	%2=extras	
		"TabHeadCol"   => '\t\t\t\t<th class="%1$s" %2$s >%3$s</th>\n', // %1 = classes %2=extras	 %3=$value  
		"TabHeadRowEnd"  => '\t\t\t</tr>\n',
		"TabHeadEnd"     => '\t\t</thead>\n',
		
		"TabFootStart"   => '\t\t<tfoot>\n',
		"TabFootRowStart"=> '\t\t\t<tr class="%1$s" %2$s >\n', // %1 = classes	%2=extras	
		"TabFootCol"   => '\t\t\t\t<td class="%1$s" %2$s >%3$s</td>\n', // %1 = classes %2=extras	 %3=$value 
		"TabFootRowEnd"  => '\t\t\t</tr>\n',
		"TabFootEnd"     => '\t\t</tfoot>\n',
		
		"TabBodyStart"   => '\t\t<tbody>\n',
		"TabRowStart"    => '\t\t\t<tr class="%1$s" %2$s >\n', // %1 = classes	%2=extras	

		"TabColLast"     => '\t\t\t\t<td class="%1$s" %2$s >%3$s</td>\n', // %1 = classes %2=extras	 %3=$value  First Column
		"TabCol"         => '\t\t\t\t<td class="%1$s" %2$s >%3$s</td>\n', // %1 = classes %2=extras	 %3=$value  Other Columns
		"TabColFirst"    => '\t\t\t\t<td class="%1$s" %2$s >%3$s</td>\n', // %1 = classes %2=extras	 %3=$value  Last Column

		"TabRowEnd"      => '\t\t\t</tr>\n',
		"TabBodyEnd"     => '\t\t</tbody>\n',	
		
		"TabEnd"         => '\t</table>\n',
		"WrapEnd"        => '</div><!-- TableWrapper -->\n'		
		
	);
	
	// IMPORTANT !!!! WE CAN USE  \n \t INSIDE SINGLEQUOTES HERE !!!!
	// Array to override single templates elements, 
	// This is applied after external templates where loaded 
	public $aTplOverride=array  ();
	
	
	//Error array internally handles all Errors
	public $aError=array();

	//the most important thing 
	public $sOutput="";
	
	/////////////////////////////////////////////////////////////////////
	//  Main Methods from here
	/////////////////////////////////////////////////////////////////////
	
	public function Create () {
		$this->_Init();
		if ($this->aError) return $this->_Error();	
		
		$this->_Build();
		if ($this->aError) return $this->_Error();	
		
		return $this->sOutput;
	}	
	
	
	private function _Init () {
	
		// some checks
		if ($this->aData == "") $this->aError[]="Dataarray does not exist! No data no table...";
		if ($this->aError) return;
		
		$this->iDataCols= count($this->aData[0]);
		if ($this->iDataCols == 0) $this->aError[]="Dataarray is somehow broken, first line empty"; 
		if ($this->aError) return;
		
		if ($this->sAdapt1D!="" AND $this->iTablify!=0) $this->aError[]="You can only use one way to convert a 1 Dimensional array Tabify or Adapt1D"; 
		if ($this->aError) return;
		
		$this->Adapt1D();
		$this->Tablify();
		
		// try to load Alternative Template
		$this->_LoadTemplate (); 
		if ($this->aError) return;	
		
		// Manually override some(maybe all) template parts
		$this->aTpl = array_replace($this->aTpl, $this->aTplOverride);
		
		//  fetch header if set so 
		$this->_FetchHeader (); 
		if ($this->aError) return;	
		
		//  fetch footer if set so 
		$this->_FetchFooter ();
		if ($this->aError) return;	
		
		// check if header , Data , Footer match in length
		$this->_CheckLength (); 
		if ($this->aError) return;	
		
		$this->iDataRows = count($this->aData);
	}
	
	private function _Build () {

		//basic wrapping elements
		$this->sOutput = sprintf ($this->aTpl['WrapStart'],$this->sWrapperClass,$this->sWrapperExtra);
		$this->sOutput .= sprintf ($this->aTpl['TabStart'],$this->sTableClass,$this->sTableExtra);
		
		//caption
		if ($this->sCaption){
			$this->sOutput .= sprintf ($this->aTpl['TabCaption'],$this->sCaptionClass,$this->sCaption);
		}
		
		//colgroup
		$this->sOutput .=$this->aTpl['TabColgroup'];
		
		//Table header
		if ($this->iHeaderCols) $this->_BuildHeader();
		if ($this->aError) return;	

		// Table Footer in real table we need it here 
		if($this->bIsTableTemplate){
			if ($this->iFooterCols) $this->_BuildFooter();		
			if ($this->aError) return;	
		}

		// generate table body
		$this->_BuildBody();
		if ($this->aError) return;	
		
		// in Div templates the footer is generated after the body
		if(!$this->bIsTableTemplate){
			if ($this->iFooterCols) $this->_BuildFooter();		
			if ($this->aError) return;	
		}
		
		//basic wrapping elements, end
		$this->sOutput .= $this->aTpl['TabEnd'];
		$this->sOutput .= $this->aTpl['WrapEnd'];
		
		//restore \n \t
		$this->sOutput = $this->_ReQuote($this->sOutput);
	
	}
		
	
	/////////////////////////////////////////////////////////////////////
	// All function stuff besides from the 3 Main functions
	/////////////////////////////////////////////////////////////////////
	
	////// used in _init //////
	
	//adapt a onedimensional array to be displayed as a 1 column/row Table
	private function Adapt1D () {
		if ($this->sAdapt1D=="col"){
			$aTempData=array();
			foreach ($this->aData as $Key=>$Value) {
				$aTempData[]=array($Key=>$Value);
			}
			$this->aData=$aTempData;	
			return;
		}
		if ($this->sAdapt1D=="row"){
			$this->aData=array($this->aData);
			
			return;
		}
	}
	
	//converts a 1 dimensional Array into a 2 dimensional one 
	private function Tablify () {
		//nothing to to
		if (!$this->iTablify) return;
		
		//keys wont help as we rearrange everything
		// and they cant be used consistent as header or footer
		$aTempData=array_values ($this->aData);
		//echo"<pre>";print_r($aTempData);echo"</pre>";
		$iPadding=0;
		$iCols=(int)$this->iTablify;
		$iElements=count($aTempData);
		
		//calculate padding
		if ($iElements<$iCols) {
			//padding = difference between elements and columns
			$iPadding= $iCols-$iElements;
		}
		if ($iElements>$iCols) {
			//calculate padding using modulo operator
			$iPadding= $iCols-($iElements % $iCols);
			if ($iPadding==$iCols) $iPadding=0;
		}

		//pad the array so it would create a complete table
		while ($iPadding!=0) {
			$aTempData[]="";
			$iPadding--;
		}
		//echo count($aTempData);
		
		//split the array
		$this->aData=array_chunk($aTempData, $iCols);
		//thats it
	}
	
	
	private function _LoadTemplate() {
		if ($this->sAlternativTemplate !=""){
			if (file_exists ( $this->sAlternativTemplate )){
				$this->aTpl = include($this->sAlternativTemplate);
			} else {
				$this->aError[]="Templatefile '".$this->sAlternativTemplate."' does not exists";
			}
		}
	}
	
	private function _FetchHeader() {
		if ($this->sHeadAutoFetch == "") return;
		//in all other cases we are going to overwrite header
		$this->aHeader=array();
		if ($this->sHeadAutoFetch == "keys"){//fetch from keys
			foreach ($this->aData[0] as $key => $value){
				$this->aHeader[]= $key;
			}
			return;
		}
		if (count($this->aData)==1) {$this->aError[]="Data too short to fetch Header"; return;}
		if ($this->sHeadAutoFetch == "first"){//fetch from top row
			$aRow = array_shift($this->aData);
			foreach ($aRow as $key => $value){
				$this->aHeader[]= $value;
			}
			return;
		}
		if ($this->sHeadAutoFetch == "last"){//fetch from bottom row
			$aRow = array_pop($this->aData);
			foreach ($aRow as $key => $value){
				$this->aHeader[]= $value;
			}
			return;
		}
	}

	private function _FetchFooter() {
		if ($this->sFootAutoFetch == "") return;
		
		//in all other cases we are going to overwrite footer
		$this->aFooter=array();
		if ($this->sFootAutoFetch == "keys"){//fetch from keys
			foreach ($this->aData[0] as $key => $value){
				$this->aFooter[]= $key;
			}
			return;
		}
		if (count($this->aData)==1) {$this->aError[]="Data too short to fetch Footer"; return;}
		if ($this->sFootAutoFetch == "first"){//fetch from top row
			$aRow = array_shift($this->aData);
			foreach ($aRow as $key => $value){
				$this->aFooter[]= $value;
			}
			return;
		}
		if ($this->sFootAutoFetch == "last"){//fetch from bottom row
			$aRow = array_pop($this->aData);
			foreach ($aRow as $key => $value){
				$this->aFooter[]= $value;
			}
			return;
		}
	}
	
	private function _CheckLength () {
		// only if we have a header , we need to do something 
		if ($this->aHeader!="") {
			$this->iHeaderCols = count($this->aHeader);
			if ($this->iHeaderCols != $this->iDataCols) 
				$this->aError[]="Header and Data are not same length! Header: ".$this->iHeaderCols." Data: ". $this->iDataCols;
		}
		
		// only if we have a footer , we need to do something 
		if ($this->aFooter!="") {
			$this->iFooterCols = count($this->aFooter);
			if ($this->iFooterCols != $this->iDataCols) 
				$this->aError[]="Footer and Data are not same length! Header: ".$this->iFooterCols." Data: ". $this->iDataCols;
		}
	}
	
	////// used in _Build //////

	private function _BuildHeader() {
		$this->sOutput.=$this->aTpl['TabHeadStart'];
	
		//we got only one row now
		 $aRow=$this->aHeader;

		//reset refault values
		$sRowExtra=$this->sDefaultTrHeadExtra;
		$aRowClasses=array();
		if ($this->sDefaultTrHeadClasses) $aRowClasses[]=$this->sDefaultTrHeadClasses;
		
		//generate row start output
		$this->sOutput .= sprintf ($this->aTpl['TabHeadRowStart'],$this->_MakeClass($aRowClasses),$sRowExtra);
		
		// column output start
		$iColCount=1;
		$iRColCount=$this->iDataCols;
		$iColType=1;
		
		//run through the columns
		foreach ($aRow as $asColumn){ //column can be array or string

			//reset defaults values
			$sColExtra=$this->sDefaultThExtra;
			$sColValue="";
			$aColClasses=array();
			if ($this->sDefaultThClasses) $aColClasses[]=$this->sDefaultThClasses;
						
			//dont display cols that contain an empty array that is the marker for don't display
			//this is used for rowspan and colspan stuff
			if (is_array($asColumn) AND empty($asColumn)) {
				//but dont forget to count counters before continue
				$iColCount++;
				$iRColCount--;
				$iColType++;
				if ($iColType>$this->iMaxColTypes) $iColType=1;
				//go to next Column
				continue;
			}
			
			//setting values if this col contains an array
			if (is_array($asColumn)) {
				if (isset($asColumn['value'])) $sColValue=$asColumn['value'];
				if (isset($asColumn['extra'])) $sColExtra.= " ".$asColumn['extra'];
				if (isset($asColumn['class'])) $aColClasses[]=$asColumn['class'];
			} else { //its just a string so set it as value
				$sColValue=$asColumn;
			}
			
			
			//add counted cols and rows
			$aColClasses[]= $this->sColHeadClass .$iColCount;
			$aColClasses[]= $this->sRColHeadClass.$iRColCount;
			
			//coltypes for colored rows and more
			$aColClasses[]= $this->sColTypeHeadClass.$iColType;
			
			//hooray here comes output 
			$this->sOutput .= sprintf ($this->aTpl['TabHeadCol'],$this->_MakeClass($aColClasses),$sColExtra,$sColValue);
			
			//count counters
				$iColCount++;
				$iRColCount--;
				$iColType++;
				if ($iColType>$this->iMaxColTypes) $iColType=1;

		} //end ($aRow as $asColumn)
		// column output end
		
		
		//output the end of the row
		$this->sOutput .= $this->aTpl['TabHeadRowEnd'];

		//output ent of table header
		$this->sOutput.=$this->aTpl['TabHeadEnd'];
	}
	
	private function _BuildFooter() {
		$this->sOutput.=$this->aTpl['TabFootStart'];
	
		//we got only one row now
		 $aRow=$this->aFooter;

		//reset refault values
		$sRowExtra=$this->sDefaultTrFootExtra;
		$aRowClasses=array();
		if ($this->sDefaultTrFootClasses) $aRowClasses[]=$this->sDefaultTrFootClasses;
		
		//generate row start output
		$this->sOutput .= sprintf ($this->aTpl['TabFootRowStart'],$this->_MakeClass($aRowClasses),$sRowExtra);
		
		// column output start
		$iColCount=1;
		$iRColCount=$this->iDataCols;
		$iColType=1;
		
		//run through the columns
		foreach ($aRow as $asColumn){ //column can be array or string

			//reset defaults values
			$sColExtra=$this->sDefaultTdFootExtra;
			$sColValue="";
			$aColClasses=array();
			if ($this->sDefaultTdFootClasses) $aColClasses[]=$this->sDefaultTdFootClasses;
						
			//dont display cols that contain an empty array that is the marker for don't display
			//this is used for rowspan and colspan stuff
			if (is_array($asColumn) AND empty($asColumn)) {
				//but dont forget to count counters before continue
				$iColCount++;
				$iRColCount--;
				$iColType++;
				if ($iColType>$this->iMaxColTypes) $iColType=1;
				//go to next Column
				continue;
			}
			
			//setting values if this col contains an array
			if (is_array($asColumn)) {
				if (isset($asColumn['value'])) $sColValue=$asColumn['value'];
				if (isset($asColumn['extra'])) $sColExtra.= " ".$asColumn['extra'];
				if (isset($asColumn['class'])) $aColClasses[]=$asColumn['class'];
			} else { //its just a string so set it as value
				$sColValue=$asColumn;
			}
			
			
			//add counted cols and rows
			$aColClasses[]= $this->sColFootClass .$iColCount;
			$aColClasses[]= $this->sRColFootClass.$iRColCount;
			
			//coltypes for colored rows and more
			$aColClasses[]= $this->sColTypeFootClass.$iColType;
			
			//hooray here comes output 
			$this->sOutput .= sprintf ($this->aTpl['TabFootCol'],$this->_MakeClass($aColClasses),$sColExtra,$sColValue);
			
			//count counters
				$iColCount++;
				$iRColCount--;
				$iColType++;
				if ($iColType>$this->iMaxColTypes) $iColType=1;

		} //end ($aRow as $asColumn)
		// column output end
		
		
		//output the end of the row
		$this->sOutput .= $this->aTpl['TabFootRowEnd'];

		//output ent of table header
		$this->sOutput.=$this->aTpl['TabFootEnd'];
	
	}	
	
	private function _BuildBody() {
		$this->sOutput.=$this->aTpl['TabBodyStart'];
	
		//set counter defaults
		$iRowCount=1;
		$iRRowCount=$this->iDataRows;
		$iRowType=1;
		
		//run through all rows
		foreach ($this->aData as $aRow) {

			//reset refault values
			$sRowExtra=$this->sDefaultTrExtra;
			$aRowClasses=array();
			if ($this->sDefaultTrClasses) $aRowClasses[]=$this->sDefaultTrClasses;
			
			//add counted rows
			$aRowClasses[]= $this->sRowClass .$iRowCount;
			$aRowClasses[]= $this->sRRowClass.$iRRowCount;
			
			//Rowtypes for colored rows and more
			$aRowClasses[]= $this->sRowTypeClass.$iRowType;
			
			//generate row start output
			$this->sOutput .= sprintf ($this->aTpl['TabRowStart'],$this->_MakeClass($aRowClasses),$sRowExtra);
			
			// column output start
			$iColCount=1;
			$iRColCount=$this->iDataCols;
			$iColType=1;
			
			//run through the columns
			foreach ($aRow as $asColumn){ //column can be array or string

				//reset defaults values
				$sColExtra=$this->sDefaultTdExtra;
				$sColValue="";
				$aColClasses=array();
				if ($this->sDefaultTdClasses) $aColClasses[]=$this->sDefaultTdClasses;
							
				//dont display cols that contain an empty array that is the marker for don't display
				//this is used for rowspan and colspan stuff
				if (is_array($asColumn) AND empty($asColumn)) {
					//but dont forget to count counters before continue
					$iColCount++;
					$iRColCount--;
					$iColType++;
					if ($iColType>$this->iMaxColTypes) $iColType=1;
					//go to next Column
					continue;
				}
				
				//setting values if this col contains an array
				if (is_array($asColumn)) {
					if (isset($asColumn['value'])) $sColValue=$asColumn['value'];
					if (isset($asColumn['extra'])) $sColExtra.= " ".$asColumn['extra'];
					if (isset($asColumn['class'])) $aColClasses[]=$asColumn['class'];
				} else { //its just a string so set it as value
					$sColValue=$asColumn;
				}
				
				
				//add counted cols and rows
				$aColClasses[]= $this->sColClass .$iColCount;
				$aColClasses[]= $this->sRColClass.$iRColCount;
				
				//coltypes for colored columns and more
				$aColClasses[]= $this->sColTypeClass.$iColType;
				
				//set row an reverse row in column
				$aColClasses[]= $this->sColRowClass .$iRowCount;
				$aColClasses[]= $this->sRColRowClass.$iRRowCount;
				
				//another template for the first and last column
				$sColTemplate="TabCol";
				if ($iColCount==1) $sColTemplate="TabColFirst";
				if ($iColCount==$this->iDataCols) $sColTemplate="TabColLast";
				
				
				//hooray here comes output 
				$this->sOutput .= sprintf ($this->aTpl[$sColTemplate],$this->_MakeClass($aColClasses),$sColExtra,$sColValue);
				
				
				//count counters
					$iColCount++;
					$iRColCount--;
					$iColType++;
					if ($iColType>$this->iMaxColTypes) $iColType=1;

			} //end ($aRow as $asColumn)
			// column output end
			
			
			//output the end of the row
			$this->sOutput .= $this->aTpl['TabRowEnd'];
			
			//all counters
			$iRowCount++;
			$iRRowCount--;
			$iRowType++;
			if ($iRowType>$this->iMaxRowTypes) $iRowType=1;
		}
		
	
		$this->sOutput.=$this->aTpl['TabBodyEnd'];
	}	
	
	
	
	/////////////////////////////////////////////////////////////////////
	// Some Helper stuff down here 
	/////////////////////////////////////////////////////////////////////
	
	private function _Error() {
	$output="";
	$output.= '<div class="att_error '.$this->sWrapperClass.'" >'."\n";
	$output.= "\t<h2>Error in TableToArray</h2>\n";
	foreach ($this->aError as $value) {
		$output.= "\t<p><b>$value</b></p>\n";
	}
	$output.= "</div>\n";		
	return $output;
	}
	
	private function _MakeId($sId){
		$sIdText = ' id="'.$sId.'" ';
		return $sIdText;
	}
	
	private function _MakeClass($aClasses){
	$sClasses=implode (" ", $aClasses);
	return $sClasses;
	}
	
	//restores functional /t /n .... that are not available in singlequotes
	private function _ReQuote($sText){
	//echo "run";
		$search = array();
		$search[0] = '/\\\n\\\r/';
		$search[1] = '/\\\n/';
		$search[2] = '/\\\t/';


		$replace = array();
		$replace[0] = "\n\r";		
		$replace[1] = "\n";
		$replace[2] = "\t";


		$sText = preg_replace($search, $replace, $sText);
	
		return $sText;
	}	
	

	

	
	//Decided against this cause its dependant on DB driver used by PHP
	//so its not the Job of this script to convert DB Results to Arrays
	//Left this here as an example.
	//As i plan on using Readbeanphp, Arrays are provided by the ORM anyway. 
	/*
	public function Sql2Array($result) {
		$myarray=array();
		while($row = mysql_fetch_assoc($result)) {
			$myarray[]= $row;
		}  
		return $myarray;
	}
	*/
	
	
}